﻿using System;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace TD.Interface.Credits
{
    internal class CharacterTexture : IDisposable
    {
        public Texture2D Texture { get { return this.texture; } }
        private Texture2D texture;
        private SpriteBatch spriteBatch;
        private SpriteFont font;
        private char key;

        public CharacterTexture(Game game, char key)
        {
            this.key = key;

            spriteBatch = new SpriteBatch(game.GraphicsDevice);
            font = game.Content.Load<SpriteFont>("QuartzMS");

            if (texture == null)
            {
                RenderTarget2D target = new RenderTarget2D(game.GraphicsDevice, 1280, 720);
                game.GraphicsDevice.SetRenderTarget(target);

                game.GraphicsDevice.Clear(Color.Black);
                spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
                spriteBatch.DrawString(font, key.ToString(), Vector2.Zero, Color.White);
                spriteBatch.End();

                game.GraphicsDevice.SetRenderTarget(null);

                Color[] data = new Color[target.Width * target.Height];
                target.GetData<Color>(data);

                // Isolate the character...
                int width = target.Width;
                int height = target.Height;
                IsolateCharacter(ref data, ref width, ref height);

                texture = new Texture2D(game.GraphicsDevice, width, height);
                texture.SetData<Color>(data);
            }
        }

        private void IsolateCharacter(ref Color[] data, ref int width, ref int height)
        {
            //
            // Now it is time to isolate the character from the rest of the image.
            //

            Point topLeft = Point.Zero;
            {
                // Top
                {
                    bool found = false;
                    for (int y = 0; (y < height && !found); y++)
                    {
                        for (int x = 0; (x < width && !found); x++)
                        {
                            if (data[(y * width) + x].R > 0x00)
                            {
                                found = true;
                                topLeft = new Point(0, y);
                            }
                        }
                    }
                }

                // Left
                {
                    bool found = false;
                    for (int x = 0; (x < width && !found); x++)
                    {
                        for (int y = 0; (y < height && !found); y++)
                        {
                            if (data[(y * width) + x].R > 0x00)
                            {
                                found = true;
                                topLeft = new Point(x, topLeft.Y);
                            }
                        }
                    }
                }
            }

            Point bottomRight = Point.Zero;
            {
                // Right
                {
                    bool found = false;
                    for (int x = width - 1; (x >= 0 && !found); x--)
                    {
                        for (int y = height - 1; (y >= 0 && !found); y--)
                        {
                            if (data[(y * width) + x].R > 0x00)
                            {
                                found = true;
                                bottomRight = new Point(x, 0);
                            }
                        }
                    }
                }

                // Bottom
                {
                    bool found = false;
                    for (int y = height - 1; (y >= 0 && !found); y--)
                    {
                        for (int x = width - 1; (x >= 0 && !found); x--)
                        {
                            if (data[(y * width) + x].R > 0x00)
                            {
                                found = true;
                                bottomRight = new Point(bottomRight.X, y);
                            }
                        }
                    }
                }
            }

#if DEBUG
            Debug.Assert(topLeft.X < bottomRight.X);
            Debug.Assert(topLeft.Y < bottomRight.Y);
#endif

            if (topLeft.X < bottomRight.X &&
                topLeft.Y < bottomRight.Y)
            {
                int tempWidth = ((bottomRight.X - topLeft.X) + 1);
                int tempHeight = ((bottomRight.Y - topLeft.Y) + 1);
                Color[] temp = new Color[tempWidth * tempHeight];

                for (int y = 0; y < tempHeight; y++)
                {
                    for (int x = 0; x < tempWidth; x++)
                    {
                        Color original = Color.FromNonPremultiplied(0xFF, 0xFF, 0xFF, data[(width * (y + topLeft.Y)) + topLeft.X + x].R);
                        temp[(y * tempWidth) + x] = original;
                    }
                }

                width = tempWidth;
                height = tempHeight;
                data = temp;
            }
            else
            {
                data = new Color[1] { Color.FromNonPremultiplied(0x00, 0x00, 0x00, 0x00) };
                width = 1;
                height = 1;
            }
        }

        public void Dispose()
        {
            if (texture != null)
            {
                texture.Dispose();
                texture = null;
            }
        }
    }
}
